/*
 * Copyright 2010 HighCraft, Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package ru.highcraft.apis.littlesms;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;

import java.lang.reflect.Type;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * User: neoasket
 * Date: 2010-09-20
 * Time: 00:46:28
 */
public class LittleSmsImpl implements LittleSms {

    private String user;
    private String apiKey;
    private String url;
    private HttpClient httpClient;
    private ResponseHandler<String> responseHandler;
    private Gson gson;

    public LittleSmsImpl() {
        this.url = "https://littlesms.ru/api/";
        this.httpClient = new DefaultHttpClient();
        this.gson = new Gson();
        this.responseHandler = new BasicResponseHandler();
    }

    public LittleSmsImpl(String user, String apiKey, String url) {
        this.user = user;
        this.apiKey = apiKey;
        this.url = url;
        this.httpClient = new DefaultHttpClient();
        this.gson = new Gson();
        this.responseHandler = new BasicResponseHandler();
    }

    @Override
    public LittleSmsResponse sendSms(String recipients, String message, String sender, Boolean test) throws Exception {
        final LinkedList<NameValuePair> nameValuePairs = new LinkedList<NameValuePair>();
        nameValuePairs.add(new BasicNameValuePair("recipients", recipients));
        nameValuePairs.add(new BasicNameValuePair("message", message));
        if (StringUtils.isNotBlank(sender)) {
            nameValuePairs.add(new BasicNameValuePair("sender", sender));
        }
        if (test != null) {
            nameValuePairs.add(new BasicNameValuePair("test", test ? "1" : "0"));
        }
        return this.makeRequest("message/send", nameValuePairs);
    }

    @Override
    public LittleSmsResponse checkBalance() throws Exception {
        final LinkedList<NameValuePair> nameValuePairs = new LinkedList<NameValuePair>();
        return this.makeRequest("user/balance", nameValuePairs);
    }

    @Override
    public LittleSmsResponse getStatus(final int[] messages_id) throws Exception {
        final String temp = Arrays.toString(messages_id).replace(", ", ",");
        final String messages_id_str = temp.substring(1, temp.length() - 1);

        final LinkedList<NameValuePair> nameValuePairs = new LinkedList<NameValuePair>();
        nameValuePairs.add(new BasicNameValuePair("messages_id", messages_id_str));
        return this.makeRequest("message/status", nameValuePairs);
    }

    @Override
    public LittleSmsResponse getPrice(String recipients, String message) throws Exception {
        final LinkedList<NameValuePair> nameValuePairs = new LinkedList<NameValuePair>();
        nameValuePairs.add(new BasicNameValuePair("recipients", recipients));
        nameValuePairs.add(new BasicNameValuePair("message", message));
        return this.makeRequest("message/price", nameValuePairs);
    }

    @Override
    public LittleSmsResponse getHistory(Integer history_id, String recipient, String sender, String status, Date date_from, Date date_to, Integer id) throws Exception {
        final LinkedList<NameValuePair> nameValuePairs = new LinkedList<NameValuePair>();
        if (history_id != null) {
            nameValuePairs.add(new BasicNameValuePair("history_id", String.valueOf(history_id)));
        }
        if (StringUtils.isNotBlank(recipient)) {
            nameValuePairs.add(new BasicNameValuePair("recipient", recipient));
        }
        if (StringUtils.isNotBlank(sender)) {
            nameValuePairs.add(new BasicNameValuePair("sender", sender));
        }
        if (StringUtils.isNotBlank(status)) {
            nameValuePairs.add(new BasicNameValuePair("status", status));
        }
        if ((date_from != null) || (date_to !=null)) {
            DateFormat dateFormat = new SimpleDateFormat(DATE_TIME_FORMAT);
            dateFormat.setTimeZone(TIME_ZONE_UTC);
            if (date_from != null) {
                nameValuePairs.add(new BasicNameValuePair("date_from", dateFormat.format(date_from)));
            }
            if (date_to != null) {
                nameValuePairs.add(new BasicNameValuePair("date_to", dateFormat.format(date_to)));
            }
        }
        if (id != null) {
            nameValuePairs.add(new BasicNameValuePair("id", String.valueOf(id)));
        }
        return this.makeRequest("message/history", nameValuePairs);
    }

    private LittleSmsResponse makeRequest(String action, final LinkedList<NameValuePair> nameValuePairs) throws Exception {
        final HttpPost httpPost = new HttpPost(this.url + action);
        nameValuePairs.addFirst(new BasicNameValuePair("user", this.user));
        nameValuePairs.add(new BasicNameValuePair("sign", this.sign(nameValuePairs)));
        httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, HTTP.UTF_8));
        final String responseBody = httpClient.execute(httpPost, responseHandler);
        if ("message/history".equals(action) || "message/status".equals(action)) {
            Type type = new TypeToken<LittleSmsResponse>() {}.getType();
            return gson.fromJson(responseBody, type);
        } else {
            return gson.fromJson(responseBody, LittleSmsResponse.class);
        }
    }

    private String sign(final List<NameValuePair> nameValuePairs) {
        final StringBuilder parameters = new StringBuilder();
        if ((nameValuePairs != null) && !nameValuePairs.isEmpty()) {
            for (NameValuePair nameValuePair : nameValuePairs) {
                parameters.append(nameValuePair.getValue());
            }
        }
        parameters.append(this.apiKey);
        return DigestUtils.md5Hex(DigestUtils.shaHex(parameters.toString()));
    }
}
